import {QuarkElement, property, customElement, createRef, state} from "quarkc"
import style from "./index.less?inline"

const KEY_CODE = {
    backspace: 8,
    left: 37,
    up: 38,
    right: 39,
    down: 40
};

@customElement({tag: "code-input", style})
class MyComponent extends QuarkElement {
    @property({type: Number}) // 外部属性
    count = 0
    @property({type: String})
    type = "number"
    @property({type: String})
    className = ''
    @property({type: Number})
    fields = 6
    @property({type: Number})
    fieldWidth = 58
    @property({type: Number})
    fieldHeight = 54

    @property({type: String})
    title = ''
    @property({type: Boolean})
    autoFocus = true
    @property({type: Boolean})
    disabled = false
    @property({type: Boolean})
    required = false

    @property({type: Boolean})
    @state()
    loading = false;
    @state()
    values = []
    iRefs = []
    pid = 0
    autoFocusIndex = 0
    data = () => {
        const {fields, values} = this;
        let vals;
        let autoFocusIndex = 0;
        if (values && values.length) {
            vals = [];
            for (let i = 0; i < fields; i++) {
                vals.push(values[i] || "");
            }
            autoFocusIndex = values.length >= fields ? 0 : values.length;
        } else {
            vals = Array(fields).fill("");
        }
        // this.iRefs = [];
        // for (let i = 0; i < fields; i++) {
        //     this.iRefs.push(`input_${i}`);
        // }
        this.pid = +new Date();
        this.values = vals;
        this.autoFocusIndex = autoFocusIndex
    }
    onFocus = (e) => {
        e.target.select(e);
    }
    onValueChange = (e) => {
        const index = parseInt(e.target.dataset.id);
        const {type, fields} = this;
        if (type === "number") {
            e.target.value = e.target.value.replace(/[^\d]/gi, "");
        }
        if (
            e.target.value === "" ||
            (type === "number" && !e.target.validity.valid)
        ) {
            return;
        }
        let next;
        const value = e.target.value;
        let {values} = this;
        values = Object.assign([], values);
        if (value.length > 1) {
            let nextIndex = value.length + index - 1;
            if (nextIndex >= fields) {
                nextIndex = fields - 1;
            }
            next = this.iRefs[nextIndex];
            const split = value.split("");
            split.forEach((item, i) => {
                const cursor = index + i;
                if (cursor < fields) {
                    values[cursor] = item;
                }
            });
            this.values = values;
        } else {
            next = this.iRefs[index + 1];
            values[index] = value;
            this.values = values;
        }

        if (next) {
            const element = next.current;
            element.focus();
            element.select();
        }

        this.triggerChange(values);
    }
    onKeyDown = (e) => {
        const index = parseInt(e.target.dataset.id);
        const prevIndex = index - 1;
        const nextIndex = index + 1;
        const prev = this.iRefs[prevIndex];
        const next = this.iRefs[nextIndex];
        switch (e.keyCode) {
            case KEY_CODE.backspace: {
                e.preventDefault();
                const vals = [...this.values];
                if (this.values[index]) {
                    vals[index] = "";
                    this.values = vals;
                    this.triggerChange(vals);
                } else if (prev) {
                    vals[prevIndex] = "";
                    prev.current.focus();
                    this.values = vals;
                    this.triggerChange(vals);
                }
                break;
            }
            case KEY_CODE.left:
                e.preventDefault();
                if (prev) {
                    prev.current.focus();
                }
                break;
            case KEY_CODE.right:
                e.preventDefault();
                if (next) {
                    next.current.focus();
                }
                break;
            case KEY_CODE.up:
            case KEY_CODE.down:
                e.preventDefault();
                break;
            default:
                // this.handleKeys[index] = true;
                break;
        }
    }
    triggerChange = (values = this.values) => {
        const {fields} = this;
        const val = values.join("");
        this.$emit("change", {
            detail: val
        });
        if (val.length >= fields) {
            this.$emit("complete", {
                detail: val
            });
        }
    }

    componentDidMount() {
        this.data();
    }

    renderTitle = () => {
        if (this.title) {
            return <p class="title">{this.title}</p>
        }
        return null
    }
    renderCodeInput = () => {
        let style = {
            width: `${this.fieldWidth}px`,
            height: `${this.fieldHeight}px`
        }
        return this.values.map((item, index) => {
            if (!this.iRefs[index]) {
                this.iRefs[index] = createRef();
            }
            return <input
                type={this.type == 'number' ? 'tel' : this.type}
                pattern={this.type == 'number' ? '[0-9]*' : null}
                autofocus={this.autoFocus && !this.loading && this.autoFocusIndex === index}
                style={style}
                data-id={index}
                value={item}
                ref={this.iRefs[index]}
                onInput={this.onValueChange}
                onFocus={this.onFocus}
                onKeyDown={this.onKeyDown}
                disabled={this.disabled}
                required={this.required}
                maxlength="1"
            />
        })
    }
    renderLoad = () => {
        let style = {
            lineHeight: `${this.fieldHeight}px`
        }
        return this.loading ? (
            <div className="loading" style={style}>
                <div className={'blur'}></div>
                <svg
                    class="spin"
                    viewBox="0 0 1024 1024"
                    data-icon="loading"
                    width="1em"
                    height="1em"
                    fill="currentColor"
                    aria-hidden="true"
                >
                    <path
                        fill="#006fff"
                        d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
                    />
                </svg>
            </div>
        ) : null
    }

    render() {
        return (
            <div className={`quark-code-input-container ${this.className || ''}`}
                 style={`width: ${this.fields * this.fieldWidth}px`}>
                {this.renderTitle()}
                <div className={'code-input'}>
                    {this.renderCodeInput()}
                </div>
                {this.renderLoad()}
            </div>
        );
    }
}

declare global {
    interface HTMLElementTagNameMap {
        "my-component": MyComponent
    }
}
